`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/08 15:29:08
// Design Name: 
// Module Name: uart_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_top#(
    parameter SYSTEM_CLK        =   50_000_000  ,
    parameter UART_BAUDRATE     =   9600        ,   // 波特率
    parameter UART_DATAWIDTH    =   8           ,   // 有效数据位位宽
    parameter UART_CHECK        =   0           ,   // 奇偶校验位，0-没有校验位 1-奇校验位 2-偶校验位
    parameter UART_STOP_WIDTH   =   1               // 停止位位宽，1或者2
)(
    input   i_clk       ,
    input   i_uart_rx   ,

    output  o_uart_tx   

    );


/*********parameter**********/
localparam      CLK_DIV_UART = SYSTEM_CLK / UART_BAUDRATE;

/*********wire***************/
wire                                clk_locked      ;
wire                                w_clk_rst       ;
wire                                w_clk_50MHz     ;
wire    [UART_DATAWIDTH - 1 : 0]    w_user_rx_data  ;
wire                                w_user_rx_valid ;
wire    [UART_DATAWIDTH - 1 : 0]    w_user_tx_data  ;
wire                                w_user_tx_valid ;
wire                                w_user_tx_ready ;
wire                                w_tx_clk        ;
wire                                w_tx_rst        ;
wire                                w_fifo_empty    ;
/*********reg****************/
reg     [UART_DATAWIDTH - 1 : 0]    r_user_rx_data_1b   ;   
reg     [UART_DATAWIDTH - 1 : 0]    r_user_rx_data_2b   ; 
reg                                 r_user_rx_valid_1b  ;
reg                                 r_user_rx_valid_2b  ;
// reg                                 r_user_tx_ready     ;
// reg                                 r_rd_en             ;
// reg                                 r_user_tx_valid     ;
reg                     r_fifo_rden     ;
reg                     r_uart_tx_valid ;
reg                     r_rden_lock     ;
reg                     r_user_tx_ready ;
/*********code*************/

clk_pll_50 u_clk_pll_50
(    
    // Clock in ports
    .clk_in1    (i_clk      ) ,       // input clk_in1
    // Status and control signals
    .locked     (clk_locked ) ,       // output locked
    // Clock out ports
    .clk_out1   (w_clk_50MHz)         // output clk_out1
    );      

assign  w_clk_rst = ~clk_locked   ;

clk_div_module #(
    .CLK_DIV_NUM                ( CLK_DIV_UART      ))
 u_rx_clk_div_module (          
    .i_clk                      ( w_clk_50MHz       ),
    .i_rst                      ( w_clk_rst         ),

    .o_clk                      ( w_rx_clk          )
);          

clk_div_module #(           
    .CLK_DIV_NUM                ( CLK_DIV_UART      ))
 u_tx_clk_div_module (          
    .i_clk                      ( w_clk_50MHz       ),
    .i_rst                      ( w_clk_rst         ),

    .o_clk                      ( w_tx_clk          )
);



rxdat_module #(
    .SYSTEM_CLK                 ( SYSTEM_CLK        ),
    .UART_BAUDRATE              ( UART_BAUDRATE     ),
    .UART_DATAWIDTH             ( UART_DATAWIDTH    ),
    .UART_CHECK                 ( UART_CHECK        ),
    .UART_STOP_WIDTH            ( UART_STOP_WIDTH   ))
 u_rxdat_module (
    .i_clk                      ( w_clk_50MHz       ),
    .i_rx_clk                   ( w_rx_clk          ),
    .i_clk_rst                  ( w_clk_rst         ),
    .i_uart_rx                  ( i_uart_rx         ),

    .o_user_rx_data             ( w_user_rx_data    ),
    .o_user_rx_valid            ( w_user_rx_valid   )
);

always @(posedge w_tx_clk,posedge w_clk_rst ) begin
    if(w_clk_rst)begin
        r_user_rx_data_1b   <=  'd0;
        r_user_rx_data_2b   <=  'd0;
        r_user_rx_valid_1b  <=  'd0;
        r_user_rx_valid_2b  <=  'd0;
    end
    else begin
        r_user_rx_data_1b   <=  w_user_rx_data;
        r_user_rx_data_2b   <=  r_user_rx_data_1b;
        r_user_rx_valid_1b  <=  w_user_rx_valid;
        r_user_rx_valid_2b  <=  r_user_rx_valid_1b;
    end
end

fifo_uart u_fifo_uart (
  .clk(w_clk_50MHz),      // input wire clk
  .din(r_user_rx_data_2b),      // input wire [7 : 0] din
  .wr_en(r_user_rx_valid_2b),  // input wire wr_en
  .rd_en(r_rd_en),  // input wire rd_en
  .dout(w_user_tx_data),    // output wire [7 : 0] dout
  .full(),    // output wire full
  .empty(w_fifo_empty)  // output wire empty
);
always@(posedge w_clk_50MHz,posedge w_clk_rst)
begin
    if(w_clk_rst)
        r_user_tx_ready <= 'd0;
    else
        r_user_tx_ready <= w_user_tx_ready;
end


always@(posedge w_clk_50MHz,posedge w_clk_rst)
begin
    if(w_clk_rst)
        r_rden_lock <= 'd0;
    else if(w_user_tx_ready && !r_user_tx_ready)
        r_rden_lock <= 'd0;
    else if(~w_fifo_empty && w_user_tx_ready)
        r_rden_lock <= 'd1;
    else 
        r_rden_lock <= r_rden_lock;
end

always@(posedge w_clk_50MHz,posedge w_clk_rst)
begin
    if(w_clk_rst)
        r_fifo_rden <= 'd0;
    else if(~w_fifo_empty && w_user_tx_ready && !r_rden_lock)
        r_fifo_rden <= 'd1;
    else 
        r_fifo_rden <= 'd0;
end

always@(posedge w_clk_50MHz,posedge w_clk_rst)
begin
    if(w_clk_rst)
        r_uart_tx_valid <= 'd0;
    else 
        r_uart_tx_valid <= r_fifo_rden;
end
// always @(posedge w_clk_50MHz,posedge w_clk_rst ) begin
//     if(w_clk_rst)
//         r_user_tx_ready <= 'd0;
//     else
//         r_user_tx_ready <= w_user_tx_ready;
// end

// always @(posedge w_clk_50MHz,posedge w_clk_rst ) begin
//     if(w_clk_rst)
//         r_rd_en <= 'd0;
//     else if(w_user_tx_ready && !r_user_tx_ready && !w_fifo_empty) 
//         r_rd_en <= 'd1;
//     else
//         r_rd_en <= 'd0;
// end

// always @(posedge w_clk_50MHz,posedge w_clk_rst ) begin
//     if(w_clk_rst)
//         r_user_tx_valid <= 'd0;
//     else
//         r_user_tx_valid <= r_rd_en;
// end

txdat_module #(
    .SYSTEM_CLK                 ( SYSTEM_CLK        ),
    .UART_BAUDRATE              ( UART_BAUDRATE     ),
    .UART_DATAWIDTH             ( UART_DATAWIDTH    ),
    .UART_CHECK                 ( UART_CHECK        ),
    .UART_STOP_WIDTH            ( UART_STOP_WIDTH   ))
 u_txdat_module (
    .i_clk                      ( w_tx_clk          ),
    .i_user_tx_data             ( w_user_tx_data ),
    .i_user_tx_valid            ( r_user_tx_valid),

    .o_uart_tx                  ( o_uart_tx         ),
    .o_user_tx_ready            ( w_user_tx_ready   ),
    // .o_tx_clk                   ( w_tx_clk          ),
    .o_tx_rst                   ( w_tx_rst          )
);


endmodule
